package ui;

import infrastructure.exceptions.operations.OperationException;
import inftrastructure.exceptions.ClientRuntimeException;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import server.IAdminInterface;

import core.AdminInterface;
import core.ServerFacade;
import dal.User;

import java.awt.*;              //for layout managers and more
import java.awt.event.*;        //for action events
import java.util.Iterator;

public class ManageUsersFrame extends JFrame{
	
	// Data members definition
	final private int USER_NAME_COLUMN_NUM = 0;
	final private int IS_ADMIN_COLUMN_NUM = 1;
	final private int USER_ID_COLUMN_NUM = 2;

	private ManageUsersFrame manageUserFrame = null;
	private User currUser = null;
	private AddUserDialog addUserDialog = null;
	private int tableRowIndex;
	private Iterator<User> usersIter = null;
	protected ClientFrame callingFrame = null;
	private IAdminInterface adminSession = null;
	
    private tableHandler tablehandler = new tableHandler();
	
	// Components Definition
	private Container mainCotainer = null;
	private JPanel leftPane = null;
	private JPanel rightPane = null;
	private JPanel buttonsPanel = new JPanel(new GridBagLayout());
	private JPanel closeButtomPanel = new JPanel(new FlowLayout());
	private String[] columnNames = {"User Name", "Is Admin"};
	private JTable usersTable = null;
	private DefaultTableModel tableModel = null;
    private JButton addUserButton = null;
    private JButton remUserButton = null;
    private JButton closeButton = null;
    private addButtonHandler addUserbuttonHandler = new addButtonHandler();
    private remButtonHandler remUserbuttonHandler = new remButtonHandler();
    private closeButtonHandler closebuttonHandler = new closeButtonHandler();
      
	public ManageUsersFrame (ClientFrame clientFrame)
	{
		// Set the title
		super("Users Managment Frame");
		
		// Set reference to manageUserFrame
		manageUserFrame = this;
		
		// Set reference to the main program
		callingFrame = clientFrame;
		
		// Get the AdminInterface session from the curr session
		adminSession = (AdminInterface)callingFrame.currClient.session;
		
		// get the main container of the JFrame
		mainCotainer = getContentPane();
		
		// Create the pans and set the layouts
		leftPane = new JPanel(new BorderLayout());
		rightPane = new JPanel(new BorderLayout());
		
		// Create table data model & disable user editing
		tableModel = new DefaultTableModel(columnNames, 10)
		{
	        public boolean isCellEditable(int rowIndex, int mColIndex)
	        {
	            return false;
	        }
	        public int getColumnCount() { return columnNames.length; }

	    };
	    
	    // Create the table with our table model
		usersTable = new JTable(tableModel);
		
		// Disable the ability to select single cell or columns from table
		usersTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		usersTable.setColumnSelectionAllowed(false);
		usersTable.setRowSelectionAllowed(true);

		// Create  Action Buttons
		addUserButton = new JButton ("Add New User");
		remUserButton = new JButton ("Remove Existing User");
		closeButton = new JButton ("Close");
		JButton[] buttons = {addUserButton, remUserButton};
		
		// Set buttons tooltips
		addUserButton.setToolTipText("Open add user dialog for adding\nnew users to the system");
		remUserButton.setToolTipText("Remove user from the system");
		
		// Link components to appropriate ActionListeners 
		addUserButton.addActionListener(addUserbuttonHandler);
		remUserButton.addActionListener(remUserbuttonHandler);
		closeButton.addActionListener(closebuttonHandler);
		usersTable.addMouseListener(tablehandler);
		
		// add components to container
		addButtonsRows(buttons, buttonsPanel);
		closeButtomPanel.add(closeButton);
		
		buttonsPanel.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createTitledBorder("Managment Actions"),
                BorderFactory.createEmptyBorder(5,5,5,5)));
		
		rightPane.add(new JScrollPane(usersTable),BorderLayout.CENTER);
		rightPane.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createTitledBorder("Users List"),
                BorderFactory.createEmptyBorder(5,5,5,5)));
		leftPane.add(buttonsPanel,BorderLayout.NORTH);
	
		mainCotainer.add(leftPane, BorderLayout.LINE_START);
		mainCotainer.add(rightPane, BorderLayout.LINE_END);
		mainCotainer.add(closeButtomPanel, BorderLayout.SOUTH);

		// Initialize the table with user records from DB
		getUserList();
		
		// Disable the option to open several ManageUserFrame
		callingFrame.ManageUsersButton.setEnabled(false);
		
		// Display the window
		setLocation(400, 300);
		pack();
		setLocationRelativeTo(null); // Locate frame at center of screen
		setResizable(false);
		setVisible(true);
		
		// if user press on X button then call the close button handler
		addWindowListener(new WindowAdapter(){
			public void windowClosing (WindowEvent e){
				closebuttonHandler.actionPerformed(null);
			}
		});
	}
	
	// Methods Definition
	private int init_confirm_display(String text)
	{
		/** This method initialize and display confirmation dialog */
		
		int choice = -1;
		try
		{
			choice = JOptionPane.showConfirmDialog(null,
					text,
	                "Deletion Confirmation",
	                JOptionPane.YES_NO_OPTION);
		}
		catch (HeadlessException e)
		{
			throw new ClientRuntimeException(e.getMessage(), e);
		}
		return choice;
	}

	private void addButtonsRows(JButton[] buttons,
            Container container)
	{
		/** This methods add components to grid using GridBagConstraints */
		
		int index;		
        int numofButtons = buttons.length;
		Insets buttonsInsets = new Insets(3,1,3,1);
		GridBagConstraints buttonsGridbagConstrains = new GridBagConstraints();

		buttonsGridbagConstrains.anchor = GridBagConstraints.NORTH;
		buttonsGridbagConstrains.gridx = 0; // Buttons at the first column
    	buttonsGridbagConstrains.fill = GridBagConstraints.HORIZONTAL;
    	buttonsGridbagConstrains.weightx = 1.0;
    	buttonsGridbagConstrains.gridwidth = 1; // each button occupies 1 cell
    	buttonsGridbagConstrains.insets = buttonsInsets;

        for (index = 0; index < (numofButtons); index++)
        {
        	buttonsGridbagConstrains.gridy = index; // Each button in a different row
        	container.add(buttons[index], buttonsGridbagConstrains);
        }
	}
	
	private void getUserList ()
	{
		/** This method select users list from DB and
		 *  displays the list in the JTable component*/
		
		String userName = new String();
		String isAdminStr = new String();
		boolean isAdmin;

		int index = 0;

		// Clear current values in table
		tableModel.setRowCount(0);
		
		try
		{
			// Get all-users iterator from the client parent frame
			usersIter = adminSession.getAllUsers();
			
			// Updating table
			while (usersIter.hasNext())
			{
				// Get user details
				currUser = usersIter.next();
				userName = currUser.getUsername();
				isAdmin = currUser.isAdministrator();
				if (isAdmin)
				{
					isAdminStr = "Yes";
				}
				else
				{
					isAdminStr = "No";
				}
				
				// Insert current user data into table's row using table data model
				String [] data = {userName, isAdminStr} ;
				tableModel.insertRow(index, data);
				index++;
			}				
		}
		catch(Exception ex)
		{
			throw new ClientRuntimeException(ex.getMessage(), ex);
		}		
	}
	
	// Inner classes definition
	protected class tableHandler extends MouseAdapter {

		public void mouseClicked(MouseEvent e)
			{
				// Get Selected row
				tableRowIndex = usersTable.getSelectedRow();
				if (e.getClickCount() == 2)
				{
			         // In this version - DO nothing
			         return;
				}
			}
	}

	
	private class addButtonHandler implements ActionListener {
		public void actionPerformed (ActionEvent e) 
		{			
			// Create and show the GUI of the Add User Dialog
			SwingUtilities.invokeLater(new Runnable() {
	            public void run() {
	            	addUserDialog = new AddUserDialog (manageUserFrame, "Add new user dialog");
	            	
	            	// Refresh users list
	            	getUserList();	            	
	        }
			});
		}
	}
	
	private class closeButtonHandler implements ActionListener {
		public void actionPerformed (ActionEvent e) 
		{			
			// Enable the adduser button in the main client frame before closing window
			callingFrame.ManageUsersButton.setEnabled(true);
			dispose();
		}
	}
	
	private class remButtonHandler implements ActionListener {
		public void actionPerformed (ActionEvent e) 
		{
			/** This method get user details from the table and delete this user
			 * from the repository */
			
			int toDelete;
			String confirmStr = null;
			
			// Get selected table's row
			tableRowIndex = usersTable.getSelectedRow();
			
			if (tableRowIndex == -1)
			{
				// No row was selected - do nothing
				return;
			}
			
			// Make sure the administrator wants to delete this user
			confirmStr = "Are you sure you want to delete user " + (String)usersTable.getValueAt(tableRowIndex, USER_NAME_COLUMN_NUM) + "?";
			toDelete = init_confirm_display(confirmStr);
			
			if (toDelete == JOptionPane.YES_OPTION)
			{
				try
				{
					// Remove user from DB
					adminSession.removeUser((String)usersTable.getValueAt(tableRowIndex, USER_NAME_COLUMN_NUM));
				}
				catch (OperationException ex)
				{
					JOptionPane.showMessageDialog(null, "Removing user " + (String)usersTable.getValueAt(tableRowIndex, USER_NAME_COLUMN_NUM)
							+ " failed on the server",
							"Error", JOptionPane.ERROR_MESSAGE);
				}
				catch(Exception ex)
				{
					throw new ClientRuntimeException(ex.getMessage(), ex);
				}
				
				// Refresh list in table
				getUserList();
			}
		}
	}
}
